/**
 * Copyright (c) 2018 苍穹跃龙
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.l.web.master.system.service.impl;

import java.beans.Introspector;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.List;

import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ClassUtils;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.l.web.master.system.entity.SysConfig;
import com.l.web.master.system.entity.config.Config;
import com.l.web.master.system.entity.config.GlobalConfig;
import com.l.web.master.system.exception.ConfigDataException;
import com.l.web.master.system.exception.ConfigException;
import com.l.web.master.system.mapper.SysConfigMapper;
import com.l.web.master.system.service.ISysConfigService;

/**
 * <p>
 * 配置 服务实现类
 * </p>
 *
 * @author 严秋旺
 * @since 2018-10-08
 */
@Service
public class SysConfigServiceImpl extends ServiceImpl<SysConfigMapper, SysConfig> implements ISysConfigService {

    private GlobalConfig globalConfig = null;
    
    private String moduleName(Class<?> clazz) {
        String shortName = ClassUtils.getShortName(clazz);
        return Introspector.decapitalize(shortName);
    }

    @Override
    public <T extends Config> T findConfig(Class<T> clazz) {
        try {
            String module = moduleName(clazz);
            EntityWrapper<SysConfig> wrapper = new EntityWrapper<>();
            wrapper.eq("module", module);
            List<SysConfig> list = baseMapper.selectList(wrapper);
            T object = clazz.newInstance();

            for (SysConfig config : list) {
                Field field = FieldUtils.getDeclaredField(clazz, config.getName(), true);

                if (field == null) {
                    throw new ConfigDataException("数据库中多出未指定的配置项，module:" + config.getModule() + ",name:"
                            + config.getName() + ",value:" + config.getValue());
                }

                Object value = ConvertUtils.convert(config.getValue(), field.getType());
                FieldUtils.writeDeclaredField(object, field.getName(), value, true);
            }

            return object;
        } catch (IllegalAccessException | InstantiationException e) {
            throw new ConfigException(e);
        }
    }

    @Override
    @Transactional
    public void saveConfig(Config config) {
        try {
            String module = moduleName(config.getClass());
            Field[] fields = FieldUtils.getAllFields(config.getClass());
            for (Field field : fields) {
                if (Modifier.isFinal(field.getModifiers()) || Modifier.isStatic(field.getModifiers())) {
                    continue;
                }

                String name = field.getName();
                Object value = FieldUtils.readDeclaredField(config, name, true);

                EntityWrapper<SysConfig> wrapper = new EntityWrapper<>();
                wrapper.eq("module", module).eq("name", name);
                SysConfig sysConfig = new SysConfig();
                sysConfig.setValue(String.valueOf(value));
                int update = baseMapper.update(sysConfig, wrapper);

                if (update == 0) {
                    sysConfig.setModule(module);
                    sysConfig.setName(name);
                    baseMapper.insert(sysConfig);
                }
            }
        } catch (IllegalAccessException e) {
            throw new ConfigException(e);
        }

    }

    @Override
    public GlobalConfig findGlobalConfig() {
        if (globalConfig == null) {
            globalConfig = findConfig(GlobalConfig.class);
        }

        return globalConfig;
    }

    @Override
    public void saveGlobalConfig(GlobalConfig globalConfig) {
        saveConfig(globalConfig);
        this.globalConfig = globalConfig;
    }
}
